#include "lib/pvmlib.h"
#include "lib/pvmsystem.h"
#include "lib/pvmdriver.h"
#include "lib/pvmvoicesource.h"
#include "lib/pvmvoice.h"
#include "lib/pvmversion.h"
#include "lib/pvmdebug.h"
#include "lib/helpers/pvminstreamhelpers.h"
#include "lib/pvmlog.h"

#include "lib/decoders/oggvorbis/pvmsourcefactoryoggvorbis.h"
#include "lib/decoders/wav/pvmsourcefactorywav.h"
#include "lib/decoders/mod/pvmsourcefactorymod.h"
#include "lib/decoders/speex/pvmsourcefactoryspeex.h"

#include "lib/memory/pvmmemory.h"

#define MAX_FACTORIES 4
#define PVM_MAX_CALLBACK_PERIOD	2000000

static pvm_bool libInitialized = false;
IPVMSourceFatcory **srcFactories = NULL;
int srcFactNum = 0;

static pvm_int32 pvmVersionHi = PVM_VERSION_HI;
static pvm_int32 pvmVersionLo = PVM_VERSION_LO;
static pvm_int32 pvmVersionRevision = PVM_REVISION;
static const pvm_char* pvmBuildDateStr = (const pvm_char*)_PVM_STR_MACRO(PVM_VER_NOW);
static const pvm_char* pvmCommitdDateStr = (const pvm_char*)_PVM_STR_MACRO(PVM_VER_COMMIT_DATE);

PVMAPI pvm_bool PVMCALL PVMMemoryInit(IPVMMemoryManager* customMemoryManager);
PVMAPI void PVMCALL PVMMemoryDeinit();
PVMAPI pvm_bool PVMCALL PVMMemoryIsInitialized();

PVMAPI pvm_int32 PVMCALL PVMGetVersion()
{
	return (pvmVersionHi<<24)|(pvmVersionLo<<16)|pvmVersionRevision;
}

PVMAPI pvm_bool PVMCALL PVMGetVersionFull(PvmVersionInfo *versionInfo)
{
	if(versionInfo==NULL)
		return 0;

	versionInfo->versionHigh = pvmVersionHi;
	versionInfo->versionLow = pvmVersionLo;
	versionInfo->revision = pvmVersionRevision;
	versionInfo->buildDate = pvmBuildDateStr;
	versionInfo->commitDate = pvmCommitdDateStr;

	return 1;
}

PVMAPI pvm_int32 PVMCALL PVMGetDriversCount()
{
	return PVMDriversCount();
}

PVMAPI pvm_int32 PVMCALL PVMGetDriverNameShort(pvm_uint32 nDriver, pvm_char* buffer, pvm_uint32 maxChars)
{
	return PVMDriverNameShort(nDriver, buffer, maxChars);
}

PVMAPI pvm_int32 PVMCALL PVMGetDriverNameFull(pvm_uint32 nDriver, pvm_char* buffer, pvm_uint32 maxChars)
{
	return PVMDriverNameFull(nDriver, buffer, maxChars);
}

PVMAPI pvm_uint32 PVMCALL PVMGetDriverTypeAndFlags(pvm_uint32 nDriver)
{
	return PVMDriverTypeAndFlags(nDriver);
}

PVMAPI pvm_uint32 PVMCALL PVMDevicesOutNum(pvm_uint32 nDriver)
{
	IPVMDriverBase* driver =  PVMDriverGet(nDriver);
	if(!driver)
		return 0;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDriverOut*)driver)->DevicesNum();
}

PVMAPI pvm_int32 PVMCALL PVMGetDeviceOutName(pvm_uint32 nDriver, pvm_int32 nDevice, pvm_char* buffer, pvm_uint32 maxLength)
{
	IPVMDriverBase* driver =  PVMDriverGet(nDriver);
	if(!driver)
		return 0;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDriverOut*)driver)->DeviceName(nDevice, buffer, maxLength);
}

PVMAPI PVMDEVICE PVMCALL PVMDeviceOutOpen(pvm_uint32 nDriver, pvm_int32 nDeivce, pvm_uint32 maxVoices, pvm_uint32 preferedSamplesPerSec, pvm_uint32 preferedBitsPerSample, pvm_uint32 preferedChanelsNum, void *additionalInfo, pvm_uint32 infoSize)
{
	IPVMDriverBase* driver =  PVMDriverGet(nDriver);
	if(!driver)
		return 0;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDriverOut*)driver)->DeviceOpen(maxVoices, preferedSamplesPerSec, preferedBitsPerSample, preferedChanelsNum, nDeivce, additionalInfo, infoSize);
}


PVMAPI void PVMCALL PVMDeviceClose(PVMDEVICE device)
{
	if(device==NULL)
		return;
	
	IPVMDriverBase* driverPtr = ((IPVMDeviceBase*)device)->GetDriver();
	if(driverPtr!=NULL)
		driverPtr->CloseDevice(((IPVMDeviceBase*)device));
	else
		((IPVMDeviceBase*)device)->DeviceClose();
}

PVMAPI pvm_uint32 PVMCALL PVMDeviceOutHardwareChanels(pvm_uint32 nDriver, pvm_int32 nDevice)
{
	IPVMDriverBase* driver = PVMDriverGet(nDriver);
	if(!driver)
		return 0;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDriverOut*)driver)->DeviceHardwareChanels(nDevice);
}

PVMAPI pvm_bool PVMCALL PVMDeviceOutEnumModes(pvm_uint32 nDriver, pvm_int32 nDeivce, TFormatEnumCallbackProc enumProc, void *param)
{
	IPVMDriverBase* driver = PVMDriverGet(nDriver);
	if(!driver)
		return 0;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDriverOut*)driver)->DeviceEnumModes(nDeivce, enumProc, param);
}

PVMAPI pvm_bool PVMCALL PVMGetDeviceOutActualFormat(PVMDEVICE device, PvmFormatInfo* formatInfo)
{
	memset(&formatInfo, 0, sizeof(PvmFormatInfo));

	if(device==NULL || formatInfo==NULL)
		return false;
	formatInfo->chanelsNum = ((IPVMDeviceBase*)device)->GetChanelsNum();
	formatInfo->bitsPerSample = ((IPVMDeviceBase*)device)->GetBitsPerSample();
	formatInfo->samplesPerSecond = ((IPVMDeviceBase*)device)->GetSamplesPerSecond();

	if(formatInfo->chanelsNum<=0 || formatInfo->bitsPerSample<=0 || formatInfo->samplesPerSecond<=0)
	{
		memset(&formatInfo, 0, sizeof(PvmFormatInfo));
		return false;
	}

	return true;
}

struct PVMFormatEnumeratorStruct
{
	pvm_uint32 formatsEnumarated;
	pvm_uint32 maxFormats;
	PvmFormatInfo* formats;
};

void PVMCALL FormatEnumCallback(pvm_uint32 chanelsNum, pvm_uint32 bitsPerSample, pvm_uint32 samplesPerSecond, void* param)
{
	PVMFormatEnumeratorStruct*	formEnumStruct = (PVMFormatEnumeratorStruct*)param;
	if(formEnumStruct==NULL)
		return;
	if((formEnumStruct->formats!=NULL)&&(formEnumStruct->formatsEnumarated<formEnumStruct->maxFormats))
	{
		formEnumStruct->formats[formEnumStruct->formatsEnumarated].chanelsNum = chanelsNum;
		formEnumStruct->formats[formEnumStruct->formatsEnumarated].bitsPerSample = bitsPerSample;
		formEnumStruct->formats[formEnumStruct->formatsEnumarated].samplesPerSecond = samplesPerSecond;
	}

	formEnumStruct->formatsEnumarated++;
}

PVMAPI pvm_int32 PVMCALL PVMDeviceOutGetModes(pvm_uint32 nDriver, pvm_int32 nDeivce, PvmFormatInfo* formats, pvm_uint32 maxFormats)
{
	IPVMDriverBase* driver = PVMDriverGet(nDriver);
	if(!driver)
		return -1;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return -1;

	PVMFormatEnumeratorStruct formEnumStruct = {0, maxFormats, formats};

	pvm_bool retVal = ((IPVMDriverOut*)driver)->DeviceEnumModes(nDeivce, FormatEnumCallback, &formEnumStruct);
	if(retVal==false)
		return -1;

	return 0;
}

PVMAPI pvm_bool PVMCALL PVMGetDriverOption(pvm_uint32 nDriver, const pvm_char* optionName, void* optionVal, pvm_uint32* optionSize)
{
	IPVMDriverBase* driver = PVMDriverGet(nDriver);
	if(!driver)
		return false;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return false;

	return ((IPVMDriverOut*)driver)->GetDriverOption(optionName, optionVal, optionSize);
}

PVMAPI pvm_bool PVMCALL PVMSetDriverOption(pvm_uint32 nDriver, const pvm_char* optionName, void* optionVal, pvm_uint32 optionSize)
{
	IPVMDriverBase* driver = PVMDriverGet(nDriver);
	if(!driver)
		return false;

	if((driver->GetDriverType()&EPVM_DTYPE_OUTPUT)==0)
		return false;

	return ((IPVMDriverOut*)driver)->SetDriverOption(optionName, optionVal, optionSize);
}

PVMAPI pvm_int32 PVMCALL PVMGetDeviceOption(PVMDEVICE device, const pvm_char* optionName, void* optionVal, pvm_uint32* optionSize)
{
	if(device==NULL)
		return 0;
	return ((IPVMDeviceBase*)device)->GetOption(optionName, optionVal, optionSize);
}

PVMAPI pvm_int32 PVMCALL PVMSetDeviceOption(PVMDEVICE device, const pvm_char* optionName, void* optionVal, pvm_uint32 optionSize)
{
	if(device==NULL)
		return 0;
	return ((IPVMDeviceBase*)device)->SetOption(optionName, optionVal, optionSize);
}

PVMAPI void PVMCALL PVMSuspendDevice(PVMDEVICE device)
{
	if(!device)
		return;
	return ((IPVMDeviceBase*)device)->Suspend();
}

PVMAPI void PVMCALL PVMResumeDevice(PVMDEVICE device)
{
	if(!device)
		return;
	return ((IPVMDeviceBase*)device)->Resume();
}

PVMAPI pvm_int32 PVMCALL PVMIsSuspendedDevice(PVMDEVICE device)
{
	if(!device)
		return -1;
	return ((IPVMDeviceBase*)device)->IsSuspended()==0?0:1;
}

PVMAPI pvm_int32 PVMCALL PVMDeviceGetCPUUsage(PVMDEVICE device)
{
	if(!device)
		return -1;
	return ((IPVMDeviceBase*)device)->GetCPUUsage();
}

PVMAPI pvm_bool PVMCALL PVMMmgIsInitialized()
{
	return PVMMemoryIsInitialized();
}

PVMAPI pvm_bool PVMCALL PVMInit(IPVMMemoryManager* customMemoryManager)
{
	if(PVMInitialized())
		return true;

	if(!PVMMemoryInit(customMemoryManager))
		return false;

	PVMLogInit();
	
	if(!PVMSystemInit())
		return false;

	PVMDebugMonitorInit();

	PVMDriversInit();

	srcFactories = (IPVMSourceFatcory**)PVMMemoryAlloc(sizeof(IPVMSourceFatcory)*MAX_FACTORIES);
	if(!srcFactories)
	{
		return false;
	}

	for(int i=0; i<MAX_FACTORIES; i++)
		srcFactories[i] = NULL;

	srcFactories[0] = PVMSourceFatcoryOggVorbis::CreateFactory();
	srcFactories[1] = PVMSourceFatcoryWAV::CreateFactory();
	srcFactories[2] = PVMSourceFatcorySpeex::CreateFactory();
	srcFactories[3] = PVMSourceFatcoryMOD::CreateFactory();

	srcFactNum = MAX_FACTORIES;
	libInitialized = true;

	return true;
}

PVMAPI void PVMCALL PVMDeinit()
{
	if(!PVMInitialized())
		return;

	PVMDriverUnloadAll();

	for(int i=0; i<srcFactNum; i++)
	{
		if(srcFactories[i]!=NULL)
			delete( srcFactories[i]);
	}

	PVMMemoryFree(srcFactories);
	srcFactories = NULL;
	srcFactNum = 0;

	PVMDebugMonitorDeinit();

	libInitialized = false;
	
	PVMSystemDeinit();
	PVMMemoryDeinit();
}

#undef MAX_FACTORIES

PVMAPI pvm_bool PVMCALL PVMLoadDriver(pvm_uint32 nDriver)
{
	if(!PVMInitialized())
		return false;


	if(!PVMDriverLoad(nDriver))
	{
		return false;
	}

	return true;
}

PVMAPI pvm_bool PVMCALL PVMInitialized()
{
	return libInitialized;
}

PVMAPI void PVMCALL PVMDeviceOutSetBufferLengthMs(PVMDEVICE device, pvm_uint32 bufferSize)
{
	if(!device)
		return;
	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return;
	((IPVMDeviceOut*)device)->SetBufferLengthMs(bufferSize);
}

PVMAPI pvm_int32 PVMCALL PVMDeviceOutGetBufferRealLengthMs(PVMDEVICE device)
{
	if(!device)
		return -1;
	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return -1;
	return ((IPVMDeviceOut*)device)->GetBufferRealLengthMs();
}

PVMAPI pvm_uint32 PVMCALL PVMGetAudioMaxCallbackPeriodMs()
{
	return PVM_MAX_CALLBACK_PERIOD;
}

PVMAPI PVMAUDIO PVMCALL PVMAudioOpenCallbacks(IPVMReadCallbacks *callbacks, void *src, pvm_uint32 options, pvm_bool* sourceOwned)
{
	if(!PVMInitialized())
		return NULL;

	IPvmInStream *stream = new PVMInCallbacksStream(callbacks, src);
	PVMAUDIO audio = PVMAudioOpenStream(stream, options, sourceOwned);
	if(!audio)
	{
		delete( stream);
	}

	return audio;
}

PVMAPI PVMAUDIO PVMCALL PVMAudioOpenStream(IPvmInStream *stream, pvm_uint32 options, pvm_bool* sourceOwned)
{
	if(!PVMInitialized())
		return NULL;

	if(sourceOwned)
		*sourceOwned = 1;

	IPvmInStream *loadStream = stream;

	if(options&EPVM_LOADTOMEMORY)
	{
		if(sourceOwned)
			*sourceOwned = 0;

		pvm_size newStreamSize = (pvm_size)stream->Size();
		if(newStreamSize<=0)
			return NULL;
		pvm_int8 *data = (pvm_int8*)PVMMemoryAlloc(newStreamSize);
		if(!data)
			return NULL;
		pvm_size readRes = stream->Read(data, newStreamSize);
		if(readRes!=newStreamSize)
		{
			PVMMemoryFree(data);
			return NULL;
		}
		loadStream = PVMHCreateMemoryInputStream(data, newStreamSize, true, NULL);
		if(!loadStream)
		{
			PVMMemoryFree(data);
			return NULL;
		}
	}


	int i;
	pvm_int8 *startData = NULL;
	pvm_int startDataSize = 0;
	for(i=0; i<srcFactNum; i++)
	{
		if(srcFactories[i]==NULL)
			continue;
		if(srcFactories[i]->CanLoad(loadStream, &startData, &startDataSize))
		{
			IPVMVoiceSource* retVal = srcFactories[i]->CreateVoiceSource(loadStream, startData, startDataSize);
			if(startData)
			{
				PVMMemoryFree(startData);
				startData = NULL;
				startDataSize = 0;
			}
			return retVal;
		}
	}

	if(startData)
	{
		PVMMemoryFree(startData);
	}

	if(options&EPVM_LOADTOMEMORY)
	{
		loadStream->Close();
	}

	if(sourceOwned)
		*sourceOwned = 0;

	return NULL;
}


PVMAPI void PVMCALL PVMAudioClose(PVMAUDIO audio)
{
	if(!audio)
		return;

	((IPVMVoiceSource*)audio)->Destroy();
}

PVMAPI pvm_int32 PVMCALL PVMAudioGetLength(PVMAUDIO audio)
{
	if(!audio)
		return -1;

	return ((IPVMVoiceSource*)audio)->GetLengthMS();
}

PVMAPI pvm_bool PVMCALL PVMGetAudioOption(PVMAUDIO audio, const pvm_char* optionName, void* optionVal, pvm_uint32* optionSize)
{
	if(!audio)
		return 0;

	return ((IPVMVoiceSource*)audio)->GetOption(optionName, optionVal, optionSize);
}

PVMAPI pvm_bool PVMCALL PVMSetAudioOption(PVMAUDIO audio, const pvm_char* optionName, void* optionVal, pvm_uint32 optionSize)
{
	if(!audio)
		return 0;

	return ((IPVMVoiceSource*)audio)->SetOption(optionName, optionVal, optionSize);
}

PVMAPI PVMAUDIOCACHE PVMCALL PVMAudioCreateCache(PVMDEVICE device, PVMAUDIO audio)
{
	if(audio==NULL)
		return NULL;

	if(!device)
		return NULL;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return NULL;

	IPVMDeviceOut* outDevice = (IPVMDeviceOut*)device;

	IPVMVoice* chanel = ((IPVMVoiceSource*)audio)->CreateVoice(outDevice->GetSamplesPerSecond(), outDevice->GetBitsPerSample(), outDevice->GetChanelsNum());

	chanel->AddRef();
	return chanel;	
}

PVMAPI void PVMCALL PVMAudioFreeCache(PVMAUDIOCACHE audioCahce)
{
	if(audioCahce==NULL)
		return;

	((IPVMVoice*)audioCahce)->Release();
}

PVMAPI pvm_int32 PVMCALL PVMAudioCahceStart(PVMDEVICE device, PVMAUDIOCACHE audioCahce, pvm_int32 loopCount, pvm_bool paused, pvm_int32 voiceNumber, TVoiceCallbackProc callbackProc, pvm_uint32 callbackPeriod, void* callbackParam)
{
	if(audioCahce==NULL)
		return -1;

	if(((IPVMVoice*)audioCahce)->IsOwned())
		return -1;

	if(!device)
		return -1;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return -1;

	IPVMDeviceOut* outDevice = (IPVMDeviceOut*)device;

	((IPVMVoice*)audioCahce)->SetPause(paused);
	((IPVMVoice*)audioCahce)->SetLoopCount(loopCount);

	pvm_int32 chanelNum = outDevice->PlayVoice(((IPVMVoice*)audioCahce), voiceNumber, callbackProc, callbackPeriod, callbackParam);

	if(chanelNum!=-1)
	{
		IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

		if(handle!=NULL&&handle->IsControlEnabled(chanelNum))
		{
			handle->ControlDisable(chanelNum);
		}
	}

	return chanelNum;
}

PVMAPI pvm_bool PVMCALL PVMIsAudioCahceStarted(PVMAUDIOCACHE audioCahce)
{
	if(audioCahce==NULL)
		return false;

	if(((IPVMVoice*)audioCahce)->IsOwned())
		return true;

	return false;
}

PVMAPI pvm_int32 PVMCALL PVMAudioStart(PVMDEVICE device, PVMAUDIO audio, pvm_int32 loopCount, pvm_bool paused, pvm_int32 voiceNumber, TVoiceCallbackProc callbackProc, pvm_uint32 callbackPeriod, void* callbackParam)
{
	if(audio==NULL)
		return -1;

	if(!device)
		return -1;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return -1;

	IPVMDeviceOut* outDevice = (IPVMDeviceOut*)device;

	IPVMVoice* chanel = ((IPVMVoiceSource*)audio)->CreateVoice(outDevice->GetSamplesPerSecond(), outDevice->GetBitsPerSample(), outDevice->GetChanelsNum());

	if(!chanel)
		return -1;

	chanel->AddRef();
	chanel->SetPause(paused);
	chanel->SetLoopCount(loopCount);

	pvm_int32 chanelNum = outDevice->PlayVoice(chanel, voiceNumber, callbackProc, callbackPeriod, callbackParam);

	if(chanelNum!=-1)
	{
		IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

		if(handle!=NULL&&handle->IsControlEnabled(chanelNum))
		{
			handle->ControlDisable(chanelNum);
		}
	}

	chanel->Release();


	return chanelNum;
}

PVMAPI pvm_bool PVMCALL PVMIsVoiceFree(PVMDEVICE device, pvm_uint32 chanelNum)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVMDeviceOut* outDevice = (IPVMDeviceOut*)device;

	return outDevice->IsVoiceFree(chanelNum);
}

PVMAPI void PVMCALL PVMDeviceOutSetGlobalVolume(PVMDEVICE device, pvm_uint32 volume)
{
	if(!device)
		return;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return;

	if(volume>256)
		volume = 256;
	//if(volume<0)
	//	volume = 0;
	((IPVMDeviceOut*)device)->SetMixingVolume(volume);
}

PVMAPI pvm_int32 PVMCALL PVMDeviceOutGetGlobalVolume(PVMDEVICE device)
{
	if(!device)
		return -1;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return -1;

	return ((IPVMDeviceOut*)device)->GetMixingVolume();
}

PVMAPI pvm_uint32 PVMCALL PVMDeviceOutGetChanelsNum(PVMDEVICE device)
{
	if(!device)
		return 0;

	return ((IPVMDeviceBase*)device)->GetChanelsNum();
}

PVMAPI pvm_uint32 PVMCALL PVMDeviceOutGetBitsPerSample(PVMDEVICE device)
{
	if(!device)
		return 0;

	return ((IPVMDeviceBase*)device)->GetBitsPerSample();
}

PVMAPI pvm_uint32 PVMCALL PVMDeviceOutGetSamplesPerSecond(PVMDEVICE device)
{
	if(!device)
		return 0;

	return ((IPVMDeviceBase*)device)->GetSamplesPerSecond();
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetPanning(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetPanning(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetPanningDirect(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetPanning(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceBeginBatchParams(PVMDEVICE device)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->BeginBatchParams();
}

PVMAPI void PVMCALL PVMVoiceEndBatchParams(PVMDEVICE device)
{
	if(!device)
		return;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return;

	((IPVMDeviceOut*)device)->EndBatchParams();
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetPanningVolumeRateDirect(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 panning, pvm_int32 volume, pvm_int32 rate)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetPanningVolumeRate(chanelNum, panning, volume, rate);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetVolume(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
	{
		return ((IPVMDeviceOut*)device)->SetVolume(chanelNum, value);
	}
	else
	{
		pvm_bool retVal = handle->SetVoiceMaxVolume(chanelNum, value);
		if(!handle->IsControlEnabled(chanelNum))
			retVal = ((IPVMDeviceOut*)device)->SetVolume(chanelNum, value);

		return retVal;
	}
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetVolumeDirect(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetVolume(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetLoopCount(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetLoopCount(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetLoopInSamples(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int64 loopFrom, pvm_int64 loopTo)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetLoopInSamples(chanelNum, loopFrom, loopTo);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetPause(PVMDEVICE device, pvm_uint32 chanelNum, pvm_bool value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetPause(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetRenderSilentVoice(PVMDEVICE device, pvm_uint32 chanelNum, pvm_bool value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetRenderSilentVoice(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetRate(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
	{
		return ((IPVMDeviceOut*)device)->SetRate(chanelNum, value);
	}
	else
	{
		if(handle->IsControlEnabled(chanelNum))
		{
			return handle->SetVoiceRate(chanelNum, value);
		}
		else
		{
			return ((IPVMDeviceOut*)device)->SetRate(chanelNum, value);
		}
	}
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetRateDirect(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

		if(!device)
		return 0;

	return ((IPVMDeviceOut*)device)->SetRate(chanelNum, value);
}


PVMAPI pvm_bool PVMCALL PVMVoiceGetPanning(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetPanning(chanelNum, *value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetVolume(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
	{
		return ((IPVMDeviceOut*)device)->GetVolume(chanelNum, *value);
	}
	else
	{
		if(handle->IsControlEnabled(chanelNum))
			return handle->GetVoiceMaxVolume(chanelNum, value);
		else
			return ((IPVMDeviceOut*)device)->GetVolume(chanelNum, *value);
	}
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetLoopCount(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetLoopCount(chanelNum, *value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetLoopInSamples(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int64* loopFrom, pvm_int64* loopTo)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetLoopInSamples(chanelNum, *loopFrom, *loopTo);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetLoopInMS(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32* loopFrom, pvm_int32* loopTo)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetLoopInMS(chanelNum, *loopFrom, *loopTo);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetPause(PVMDEVICE device, pvm_uint32 chanelNum, pvm_bool* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetPause(chanelNum, *value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetRenderSilentVoice(PVMDEVICE device, pvm_uint32 chanelNum, pvm_bool* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetRenderSilentVoice(chanelNum, *value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetRate(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;


	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
	{
		return ((IPVMDeviceOut*)device)->GetRate(chanelNum, *value);
	}
	else
	{
		if(handle->IsControlEnabled(chanelNum))
		{
			return handle->GetVoiceRate(chanelNum, value);
		}
		else
		{
			return ((IPVMDeviceOut*)device)->GetRate(chanelNum, *value);
		}
	}
}

PVMAPI void PVMCALL PVMVoiceStop(PVMDEVICE device, pvm_uint32 chanelNum)
{
	if(!device)
		return;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return;

	((IPVMDeviceOut*)device)->StopVoice(chanelNum);
}

PVMAPI pvm_bool PVMCALL PVMGetVoiceOption(PVMDEVICE device, pvm_uint32 chanelNum, const pvm_char* optionName, void* optionVal, pvm_uint32* optionSize)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	((IPVMDeviceOut*)device)->GetVoiceOption(chanelNum, optionName, optionVal, optionSize);
	return 1;
}

PVMAPI pvm_bool PVMCALL PVMSetVoiceOption(PVMDEVICE device, pvm_uint32 chanelNum, const pvm_char* optionName, void* optionVal, pvm_uint32 optionSize)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	((IPVMDeviceOut*)device)->SetVoiceOption(chanelNum, optionName, optionVal, optionSize);
	return 1;
}

PVMAPI pvm_bool PVMCALL PVMVoiceSetPositionMS(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32 value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	return ((IPVMDeviceOut*)device)->SetPositionMS(chanelNum, value);
}

PVMAPI pvm_bool PVMCALL PVMVoiceGetPositionMS(PVMDEVICE device, pvm_uint32 chanelNum, pvm_int32* value)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	if(value==0)
		return 0;

	return ((IPVMDeviceOut*)device)->GetPositionMS(chanelNum, *value);
}

PVMAPI pvm_bool PVMCALL PVMGetParamRange(pvm_uint32 paramId, pvm_int32* minValue, pvm_int32* maxValue, pvm_int32* defaultValue)
{
	if(minValue==NULL||maxValue==NULL||defaultValue==NULL)
		return false;

	switch(paramId)
	{
	case EPARAM_VOLUME:
		*minValue = 0; *maxValue = 256; *defaultValue = 256;
		break;
	case EPARAM_PANNING:
		*minValue = -256; *maxValue = 256; *defaultValue = 0;
		break;
	case EPARAM_RATE:
		*minValue = 1; *maxValue = 500; *defaultValue = 100;
		break;
	default:
		return false;
	};
	return true;
}

//--------------------------------------------------------------------------------
PVMAPI pvm_int32 PVMCALL PVMDeviceGet3dSupportFlags(PVMDEVICE device)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;


	return ((IPVMDeviceOut*)device)->Get3dSupportFlags();
}

PVMAPI pvm_bool PVMCALL PVMDeviceChoose3d(PVMDEVICE device, pvm_int32 i3dType)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;


	return ((IPVMDeviceOut*)device)->Choose3dInterface(i3dType);
}

//!!!!
PVMAPI pvm_int32 PVMCALL PVM3DGetRealizationType(PVMDEVICE device)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetRealizationType();
}


PVMAPI void PVMCALL PVM3DUpdate(PVMDEVICE device)
{
	if(!device)
		return;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return;

	handle->Update();
}

PVMAPI pvm_bool PVMCALL PVM3DEnable(PVMDEVICE device)
{
	if(!device)
		return false;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return false;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return false;

	return handle->Enable();
}

PVMAPI void PVMCALL PVM3DDisable(PVMDEVICE device)
{
	if(!device)
		return;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return;

	handle->Disable();
}

PVMAPI pvm_int32 PVMCALL PVM3DGetSupportedDistanceModels(PVMDEVICE device)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	pvm_int32 model = 0;

	if(!handle->GetSupportedDistanceModels(&model))
		return 0;

	return model;
}

PVMAPI pvm_bool PVMCALL PVM3DSetDistanceModel(PVMDEVICE device, pvm_int32 model)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetDistanceModel(model);
}

PVMAPI pvm_int32 PVMCALL PVM3DGetDistanceModel(PVMDEVICE device)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	pvm_int32 model = 0;

	if(!handle->GetDistanceModel(&model))
		return 0;

	return model;
}

PVMAPI pvm_bool PVMCALL PVM3DControlEnable(PVMDEVICE device, pvm_int32 chanelNum)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	pvm_int32 volume = 0;
	pvm_int32 rate = 0;
	pvm_bool volumeRet, rateRet;

	volumeRet = ((IPVMDeviceOut*)device)->GetVolume(chanelNum, volume);
	rateRet = ((IPVMDeviceOut*)device)->GetRate(chanelNum, rate);

	pvm_bool ret_val = handle->ControlEnable(chanelNum);
	if(ret_val)
	{
		if(volumeRet)
			handle->SetVoiceMaxVolume(chanelNum, volume);
		if(rateRet)
			handle->SetVoiceRate(chanelNum, rate);
	}

	return ret_val;
}

PVMAPI pvm_bool PVMCALL PVM3DControlDisable(PVMDEVICE device, pvm_int32 chanelNum)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	pvm_int32 volume = 0;
	pvm_int32 rate = 0;
	pvm_bool ret_val;
	pvm_bool getVolumeRes = handle->GetVoiceMaxVolume(chanelNum, &volume);
	pvm_bool getRateRes = handle->GetVoiceRate(chanelNum, &rate);
	
	ret_val = handle->ControlDisable(chanelNum);
	if(ret_val!=false)
	{
		if(getVolumeRes!=false)
			((IPVMDeviceOut*)device)->SetVolume(chanelNum, volume);

		if(getRateRes!=false)
			((IPVMDeviceOut*)device)->SetRate(chanelNum, rate);
	}

	return ret_val;
}


PVMAPI pvm_bool PVMCALL PVM3DSetStopOnDistance(PVMDEVICE device, pvm_int32 chanelNum, pvm_bool flag)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetStopOnDistance(chanelNum, flag);
}

PVMAPI pvm_bool PVMCALL PVM3DGetStopOnDistance(PVMDEVICE device, pvm_int32 chanelNum, pvm_bool* flag)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetStopOnDistance(chanelNum, flag);

}

//scalar dependent
//floating point
PVMAPI pvm_bool PVMCALL PVM3DSetListenerPositionF(PVMDEVICE device, float x, float y, float z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetListenerPosition_f(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetListenerVelocityF(PVMDEVICE device, float x, float y, float z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetListenerVelocity_f(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetListenerOrientationF(PVMDEVICE device, float xFront, float yFront, float zFront, float xTop, float yTop, float zTop)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetListenerOrientation_f(xFront, yFront, zFront, xTop, yTop, zTop);
}

PVMAPI pvm_bool PVMCALL PVM3DSetDopplerFactorF(PVMDEVICE device, float factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetDopplerFactor_f(factor);
}

PVMAPI pvm_bool PVMCALL PVM3DSetUnitSizeF(PVMDEVICE device, float size)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetUnitSize_f(size);
}
//************************************************************************
PVMAPI pvm_bool PVMCALL PVM3DGetListenerPositionF(PVMDEVICE device, float* x, float* y, float* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetListenerPosition_f(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetListenerVelocityF(PVMDEVICE device, float* x, float* y, float* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetListenerVelocity_f(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetListenerOrientationF(PVMDEVICE device, float* xFront, float* yFront, float* zFront, float* xTop, float* yTop, float* zTop)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetListenerOrientation_f(xFront, yFront, zFront, xTop, yTop, zTop);
}

PVMAPI pvm_bool PVMCALL PVM3DGetDopplerFactorF(PVMDEVICE device, float* factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetDopplerFactor_f(factor);
}

PVMAPI pvm_bool PVMCALL PVM3DGetUnitSizeF(PVMDEVICE device, float* size)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetUnitSize_f(size);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoicePositionF(PVMDEVICE device, pvm_int32 chanelNum, float x, float y, float z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoicePosition_f(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceVelocityF(PVMDEVICE device, pvm_int32 chanelNum, float x, float y, float z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceVelocity_f(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceDirectionF(PVMDEVICE device, pvm_int32 chanelNum, float x, float y, float z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceDirection_f(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceMinDistanceF(PVMDEVICE device, pvm_int32 chanelNum, float d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceMinDistance_f(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceMaxDistanceF(PVMDEVICE device, pvm_int32 chanelNum, float d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceMaxDistance_f(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DSetRolloffFactorF(PVMDEVICE device, pvm_int32 chanelNum, float factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetRolloffFactor_f(chanelNum, factor);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoicePositionF(PVMDEVICE device, pvm_int32 chanelNum, float* x, float* y, float* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoicePosition_f(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceVelocityF(PVMDEVICE device, pvm_int32 chanelNum, float* x, float* y, float* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceVelocity_f(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceDirectionF(PVMDEVICE device, pvm_int32 chanelNum, float* x, float* y, float* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceDirection_f(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceMinDistanceF(PVMDEVICE device, pvm_int32 chanelNum, float* d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceMinDistance_f(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceMaxDistanceF(PVMDEVICE device, pvm_int32 chanelNum, float* d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceMaxDistance_f(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DGetRolloffFactorF(PVMDEVICE device, pvm_int32 chanelNum, float* factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetRolloffFactor_f(chanelNum, factor);
}
//fixed point

//////////////////////////////////////////
//***************************************************
PVMAPI pvm_bool PVMCALL PVM3DSetListenerPositionX(PVMDEVICE device, pvm_int32 x, pvm_int32 y, pvm_int32 z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetListenerPosition_x(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetListenerVelocityX(PVMDEVICE device, pvm_int32 x, pvm_int32 y, pvm_int32 z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetListenerVelocity_x(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetListenerOrientationX(PVMDEVICE device, pvm_int32 xFront, pvm_int32 yFront, pvm_int32 zFront, pvm_int32 xTop, pvm_int32 yTop, pvm_int32 zTop)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetListenerOrientation_x(xFront, yFront, zFront, xTop, yTop, zTop);
}

PVMAPI pvm_bool PVMCALL PVM3DSetDopplerFactorX(PVMDEVICE device, pvm_int32 factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetDopplerFactor_x(factor);
}

PVMAPI pvm_bool PVMCALL PVM3DSetUnitSizeX(PVMDEVICE device, pvm_int32 size)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetUnitSize_x(size);
}

PVMAPI pvm_bool PVMCALL PVM3DGetListenerPositionX(PVMDEVICE device, pvm_int32* x, pvm_int32* y, pvm_int32* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetListenerPosition_x(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetListenerVelocityX(PVMDEVICE device, pvm_int32* x, pvm_int32* y, pvm_int32* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetListenerVelocity_x(x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetListenerOrientationX(PVMDEVICE device, pvm_int32* xFront, pvm_int32* yFront, pvm_int32* zFront, pvm_int32* xTop, pvm_int32* yTop, pvm_int32* zTop)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetListenerOrientation_x(xFront, yFront, zFront, xTop, yTop, zTop);
}

PVMAPI pvm_bool PVMCALL PVM3DGetDopplerFactorX(PVMDEVICE device, pvm_int32* factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetDopplerFactor_x(factor);
}

PVMAPI pvm_bool PVMCALL PVM3DGetUnitSizeX(PVMDEVICE device, pvm_int32* size)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetUnitSize_x(size);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoicePositionX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32 x, pvm_int32 y, pvm_int32 z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoicePosition_x(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceVelocityX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32 x, pvm_int32 y, pvm_int32 z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceVelocity_x(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceDirectionX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32 x, pvm_int32 y, pvm_int32 z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceDirection_x(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceMinDistanceX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32 d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceMinDistance_x(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DSetVoiceMaxDistanceX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32 d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetVoiceMaxDistance_x(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DSetRolloffFactorX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32 factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->SetRolloffFactor_x(chanelNum, factor);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoicePositionX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32* x, pvm_int32* y, pvm_int32* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoicePosition_x(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceVelocityX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32* x, pvm_int32* y, pvm_int32* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceVelocity_x(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceDirectionX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32* x, pvm_int32* y, pvm_int32* z)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceDirection_x(chanelNum, x, y, z);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceMinDistanceX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32* d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceMinDistance_x(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DGetVoiceMaxDistanceX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32* d)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetVoiceMaxDistance_x(chanelNum, d);
}

PVMAPI pvm_bool PVMCALL PVM3DGetRolloffFactorX(PVMDEVICE device, pvm_int32 chanelNum, pvm_int32* factor)
{
	if(!device)
		return 0;

	if((((IPVMDeviceBase*)device)->GetDeviceType()&EPVM_DTYPE_OUTPUT)==0)
		return 0;

	IPVM3DInterface* handle = ((IPVMDeviceOut*)device)->Get3dInterface();

	if(!handle)
		return 0;

	return handle->GetRolloffFactor_x(chanelNum, factor);
}

PVMAPI void PVMCALL PVMOnIdle()
{
	pvm_int driversCount = PVMDriversCount();
	for(int i=0; i<driversCount; i++)
	{
		IPVMDriverBase* driver =  PVMDriverGet(i);
		if(!driver)
			continue;

		driver->OnIdle();
	}
}